home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / lib / ubiquity / bin / ubiquity
Text File  |  2009-10-28  |  16KB  |  460 lines

  1. #!/usr/bin/python
  2.  
  3. '''
  4. Installer
  5.  
  6. This is a installer program for a Ubuntu or Metadistros Live system.
  7. This is the main program, but there are also a couple of libraries to
  8. help it to work, such as the frontend.
  9. The way it works is simple. It detects the frontend to use, then
  10. load the module for that frontend. After that, it makes some calls
  11. through the frontend in order to get the info necessary to install.
  12.  
  13. Once it has the info, partitioning, format, copy the distro to the disk
  14. and configure everything.
  15. '''
  16.  
  17. import sys
  18. import os
  19. import errno
  20. import fcntl
  21. import shutil
  22. import syslog
  23. import atexit
  24. import optparse
  25. import subprocess
  26.  
  27. sys.path.insert(0, '/usr/lib/ubiquity')
  28.  
  29. from ubiquity import misc
  30. from ubiquity import im_switch
  31.  
  32. VERSION = '2.0.8'
  33. TARGET = '/target'
  34. LOCKFILE = '/var/lock/ubiquity'
  35. lock = None
  36.  
  37. def distribution():
  38.     """Returns the name of the running distribution."""
  39.  
  40.     proc = subprocess.Popen(['lsb_release', '-is'], stdout=subprocess.PIPE)
  41.     return proc.communicate()[0].strip()
  42.  
  43. def disable_autologin():
  44.     import traceback
  45.  
  46.     # Reverse actions of user-setup-apply.
  47.     for name in ('/etc/gdm/custom.conf', '/etc/kde4/kdm/kdmrc'):
  48.         if os.path.exists('%s.oem' % name):
  49.             try:
  50.                 os.rename('%s.oem' % name, name)
  51.             except OSError:
  52.                 traceback.print_exc()
  53.  
  54. def open_terminal():
  55.     """Set up the terminal to run ubiquity's debconf frontend."""
  56.  
  57.     # Set up a framebuffer and start bterm if debian-installer/framebuffer
  58.     # says to do so. See
  59.     # rootskel/src/lib/debian-installer-startup.d/S40framebuffer-module-linux-x86.
  60.     # TODO: more careful architecture handling
  61.  
  62.     import debconf
  63.  
  64.     if 'UBIQUITY_BTERM' not in os.environ:
  65.         os.environ['UBIQUITY_BTERM'] = '1'
  66.  
  67.         framebuffer = False
  68.         dccomm = subprocess.Popen(['debconf-communicate',
  69.                                    '-fnoninteractive', 'ubiquity'],
  70.                                   stdin=subprocess.PIPE,
  71.                                   stdout=subprocess.PIPE, close_fds=True)
  72.         try:
  73.             dc = debconf.Debconf(read=dccomm.stdout, write=dccomm.stdin)
  74.             try:
  75.                 if dc.get('debian-installer/framebuffer') == 'true':
  76.                     framebuffer = True
  77.             except debconf.DebconfError:
  78.                 pass
  79.         finally:
  80.             dccomm.stdin.close()
  81.             dccomm.wait()
  82.  
  83.         if framebuffer:
  84.             def fb_has(substring):
  85.                 try:
  86.                     fb = open('/proc/fb')
  87.                 except IOError:
  88.                     return False
  89.                 try:
  90.                     for line in fb:
  91.                         if substring in line:
  92.                             return True
  93.                 finally:
  94.                     fb.close()
  95.                 return False
  96.  
  97.             got_fb = False
  98.             if fb_has('VESA'):
  99.                 got_fb = True
  100.  
  101.             devnull = open('/dev/null', 'w')
  102.  
  103.             if not got_fb:
  104.                 subprocess.call(['modprobe', '-q', 'vesafb'],
  105.                                 stdout=devnull, stderr=devnull)
  106.                 if fb_has(''):
  107.                     got_fb = True
  108.  
  109.             if not got_fb:
  110.                 subprocess.call(['modprobe', '-q', 'vga16fb'],
  111.                                 stdout=devnull, stderr=devnull)
  112.                 if fb_has(''):
  113.                     got_fb = True
  114.  
  115.             if got_fb:
  116.                 if not os.path.isdir('/sys/class/graphics/fbcon'):
  117.                     subprocess.call(['modprobe', '-q', 'fbcon'],
  118.                                     stdout=devnull, stderr=devnull)
  119.  
  120.                 # TODO: import debian-installer-utils and use update-dev?
  121.                 subprocess.call(['udevadm', 'settle'])
  122.  
  123.             devnull.close()
  124.  
  125.             if os.path.exists('/dev/fb0'):
  126.                 bterm_args = ['bterm',
  127.                               '-f', '/usr/share/ubiquity/unifont.bgf', '--']
  128.                 bterm_args.extend(sys.argv)
  129.                 os.execvp('bterm', bterm_args)
  130.  
  131.     # Start a new session and start a controlling terminal. Approach loosely
  132.     # borrowed from util-linux.
  133.  
  134.     if 'UBIQUITY_CTTY' not in os.environ:
  135.         os.environ['UBIQUITY_CTTY'] = '1'
  136.  
  137.         import fcntl
  138.         import termios
  139.  
  140.         try:
  141.             os.setsid()
  142.         except OSError:
  143.             pass
  144.  
  145.         ttyn = os.ttyname(0)
  146.         tty = os.open(ttyn, os.O_RDWR | os.O_NONBLOCK)
  147.         flags = fcntl.fcntl(tty, fcntl.F_GETFL)
  148.         fcntl.fcntl(tty, fcntl.F_SETFL, flags)
  149.         # Leave stderr alone in the following; it's already redirected to
  150.         # our log file.
  151.         for i in range(tty):
  152.             if i != 2:
  153.                 os.close(i)
  154.         for i in range(2):
  155.             if tty != i:
  156.                 os.dup2(tty, i)
  157.         if tty >= 3:
  158.             os.close(tty)
  159.  
  160.         fcntl.ioctl(0, termios.TIOCSCTTY, 1)
  161.  
  162. def start_debconf():
  163.     """debconf_ui needs to run within a debconf frontend."""
  164.  
  165.     if 'DEBIAN_HAS_FRONTEND' in os.environ:
  166.         # debconf already started, so just clean up the configuration file
  167.         # if any (debconf has already read it by now).
  168.         if 'DEBCONF_SYSTEMRC' in os.environ:
  169.             try:
  170.                 os.unlink(os.environ['DEBCONF_SYSTEMRC'])
  171.             except OSError:
  172.                 pass
  173.         return
  174.  
  175.     print >>sys.stderr, "debconf_ui selected; starting debconf frontend"
  176.  
  177.     if 'DEBCONF_USE_CDEBCONF' not in os.environ:
  178.         # This is rather unsatisfactory. Perhaps it would be better to
  179.         # have a custom debconf program, a bit like dpkg-reconfigure.
  180.         import tempfile
  181.         debconfrc_fd, debconfrc = tempfile.mkstemp()
  182.         os.chmod(debconfrc, 0644)
  183.         debconfrc_file = os.fdopen(debconfrc_fd, 'w')
  184.         orig_debconfrc = open('/etc/debconf.conf')
  185.         state = 0
  186.         for line in orig_debconfrc:
  187.             if (state == 0 and
  188.                 line.rstrip('\n') and not line.startswith('#')):
  189.                 state = 1
  190.             elif state == 1 and not line.rstrip('\n'):
  191.                 print >>debconfrc_file, 'Reshow: true'
  192.                 state = 2
  193.             print >>debconfrc_file, line,
  194.         orig_debconfrc.close()
  195.         debconfrc_file.close()
  196.         os.environ['DEBCONF_SYSTEMRC'] = debconfrc
  197.  
  198.         os.environ['DEBCONF_PACKAGE'] = 'ubiquity'
  199.     else:
  200.         os.environ['DEBCONF_SHOWOLD'] = 'true'
  201.         # TODO: need to set owner somehow
  202.  
  203.     import debconf
  204.     debconf.runFrontEnd() # re-execs this program
  205.  
  206. def install(frontend=None, query=False):
  207.     '''install(frontend=None) -> none
  208.     
  209.     Get the type of frontend to use and load the module for that.
  210.     If frontend is None, defaults to the first of mythbuntu_ui, 
  211.     gtk_ui, kde_ui, and debconf_ui that exists.
  212.     '''
  213.     if frontend is None:
  214.         frontends = ['mythbuntu_ui', 'gtk_ui', 'kde_ui', 'debconf_ui']
  215.     else:
  216.         frontends = [frontend]
  217.     chosen = None
  218.     mod = __import__('ubiquity.frontend', globals(), locals(), frontends)
  219.     for f in frontends:
  220.         if hasattr(mod, f):
  221.             chosen = f
  222.             ui = getattr(mod, f)
  223.             # Noninteractive implies automatic mode.
  224.             if f == 'noninteractive':
  225.                 os.environ['UBIQUITY_AUTOMATIC'] = '1'
  226.             # Migration Assistant does not support KDE.
  227.             if f == 'kde_ui':
  228.                 if 'UBIQUITY_MIGRATION_ASSISTANT' in os.environ:
  229.                     del os.environ['UBIQUITY_MIGRATION_ASSISTANT']
  230.             break
  231.     else:
  232.         raise AttributeError, ('No frontend available; tried %s' %
  233.                                ', '.join(frontends))
  234.     os.environ['UBIQUITY_FRONTEND'] = chosen
  235.     if query:
  236.         print >> sys.__stdout__, os.environ['UBIQUITY_FRONTEND']
  237.         sys.exit(0)
  238.  
  239.     unmount_target()
  240.     distro = distribution().lower()
  241.     wizard = ui.Wizard(distro)
  242.     if os.environ['UBIQUITY_FRONTEND'] == 'debconf_ui':
  243.         open_terminal()
  244.         start_debconf()
  245.     ret = wizard.run()
  246.     copy_debconf()
  247.     unmount_target()
  248.     if ret == 10:
  249.         wizard.do_reboot()
  250.  
  251. def copy_debconf():
  252.     """Copy a few important questions into the installed system."""
  253.     if not TARGET:
  254.         return
  255.     targetdb = TARGET + '/var/cache/debconf/config.dat'
  256.     # xserver-xorg is temporary, pending a rework of bullet-proof-x; but
  257.     # note that xserver-xorg/config/inputdevice/keyboard/* is still needed
  258.     for q in ('^console-setup/','^xserver-xorg/'):
  259.         misc.execute('debconf-copydb', 'configdb', 'targetdb', '-p', q,
  260.                      '--config=Name:targetdb', '--config=Driver:File',
  261.                      '--config=Filename:%s' % targetdb)
  262.  
  263. def unmount_target():
  264.     if not TARGET:
  265.         return
  266.     paths = []
  267.     mounts = open('/proc/mounts')
  268.     for line in mounts:
  269.         path = line.split(' ')[1]
  270.         if path == TARGET or path.startswith(TARGET + '/'):
  271.             paths.append(path)
  272.     mounts.close()
  273.     paths.sort()
  274.     paths.reverse()
  275.     for path in paths:
  276.         misc.execute('umount', path)
  277.  
  278. def prepend_path(directory):
  279.     if 'PATH' in os.environ and os.environ['PATH'] != '':
  280.         os.environ['PATH'] = '%s:%s' % (directory, os.environ['PATH'])
  281.     else:
  282.         os.environ['PATH'] = directory
  283.  
  284. def release_lock():
  285.     global lock
  286.     try:
  287.         os.unlink(LOCKFILE)
  288.     except OSError:
  289.         pass
  290.     if lock is not None:
  291.         lock.close()
  292.         lock = None
  293.  
  294. def acquire_lock():
  295.     global lock
  296.     lock = open(LOCKFILE, 'w')
  297.     try:
  298.         fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
  299.     except IOError, e:
  300.         if e.errno in (errno.EACCES, errno.EAGAIN, errno.EWOULDBLOCK):
  301.             print "Ubiquity is already running!"
  302.             sys.exit(1)
  303.         raise
  304.     atexit.register(release_lock)
  305.     fcntl.fcntl(lock, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
  306.     print >>lock, os.getpid()
  307.     lock.flush()
  308.     os.fsync(lock.fileno())
  309.  
  310. def run_oem_hooks():
  311.     """Run hook scripts from /usr/lib/oem-config/post-install."""
  312.  
  313.     hookdir = '/usr/lib/oem-config/post-install'
  314.  
  315.     if os.path.isdir(hookdir):
  316.         # Exclude hooks containing '.', so that *.dpkg-* et al are avoided.
  317.         hooks = filter(lambda entry: '.' not in entry, os.listdir(hookdir))
  318.         child_env = dict(os.environ)
  319.         child_env['DEBIAN_FRONTEND'] = 'noninteractive'
  320.         if 'DEBIAN_HAS_FRONTEND' in child_env:
  321.             del child_env['DEBIAN_HAS_FRONTEND']
  322.         for hookentry in hooks:
  323.             hook = os.path.join(hookdir, hookentry)
  324.             if os.access(hook, os.X_OK):
  325.                 # Errors are ignored at present, although this may change.
  326.                 subprocess.call([hook], env=child_env)
  327.  
  328. def main(oem_config):
  329.     usage = '%prog [options] [frontend]'
  330.     parser = optparse.OptionParser(usage=usage, version=VERSION)
  331.     parser.set_defaults(
  332.         debug=('UBIQUITY_DEBUG' in os.environ),
  333.         debug_pdb=False,
  334.         cdebconf=False,
  335.         automatic=False,
  336.         query=False,
  337.         migration_assistant=(not oem_config))
  338.     parser.add_option('-d', '--debug', dest='debug', action='store_true',
  339.                       help='debug mode (warning: passwords will be logged!)')
  340.     parser.add_option('--pdb', dest='debug_pdb', action='store_true',
  341.                       help='drop into Python debugger on a crash')
  342.     parser.add_option('--cdebconf', dest='cdebconf', action='store_true',
  343.                       help='use cdebconf instead of debconf (experimental)')
  344.     if not oem_config:
  345.         parser.add_option('--no-migration-assistant', dest='migration_assistant',
  346.                           action='store_false',
  347.                           help='disable Migration Assistant')
  348.     parser.add_option('--automatic', dest='automatic', action='store_true',
  349.                       help='do not ignore the "seen" flag (useful for ' \
  350.                       'unattended installations).')
  351.     parser.add_option('--only', dest='only', action='store_true',
  352.                       help='tell the application that it is the only desktop ' \
  353.                       'program running so that it can customize its UI to ' \
  354.                       'better suit a minimal environment.')
  355.     parser.add_option('-q', '--query', dest='query', action='store_true',
  356.                       help='find out which frontend will be used by default')
  357.     (options, args) = parser.parse_args()
  358.  
  359.     if options.debug:
  360.         os.environ['UBIQUITY_DEBUG'] = '1'
  361.  
  362.     if options.debug_pdb:
  363.         os.environ['UBIQUITY_DEBUG_PDB'] = '1'
  364.  
  365.     if options.cdebconf:
  366.         # Note that this needs to be set before DebconfCommunicate is
  367.         # imported by anything.
  368.         os.environ['DEBCONF_USE_CDEBCONF'] = '1'
  369.         prepend_path('/usr/lib/cdebconf')
  370.     prepend_path('/usr/lib/ubiquity/compat')
  371.  
  372.     if options.automatic:
  373.         os.environ['UBIQUITY_AUTOMATIC'] = '1'
  374.  
  375.     if options.migration_assistant:
  376.         os.environ['UBIQUITY_MIGRATION_ASSISTANT'] = '1'
  377.  
  378.     if options.only:
  379.         os.environ['UBIQUITY_ONLY'] = '1'
  380.  
  381.     if oem_config:
  382.         os.environ['UBIQUITY_OEM_USER_CONFIG'] = '1'
  383.         global TARGET
  384.         TARGET = ''
  385.  
  386.     acquire_lock()
  387.  
  388.     if not os.path.exists('/var/log/installer'):
  389.         os.makedirs('/var/log/installer')
  390.     syslog.openlog('ubiquity', syslog.LOG_NOWAIT | syslog.LOG_PID)
  391.  
  392.     if oem_config:
  393.         syslog.syslog("Ubiquity %s (oem-config)" % VERSION)
  394.     else:
  395.         syslog.syslog("Ubiquity %s" % VERSION)
  396.     version_file = open('/var/log/installer/version', 'w')
  397.     print >>version_file, 'ubiquity %s' % VERSION
  398.     version_file.close()
  399.  
  400.     if 'UBIQUITY_DEBUG' in os.environ:
  401.         if 'UBIQUITY_DEBUG_CORE' not in os.environ:
  402.             os.environ['UBIQUITY_DEBUG_CORE'] = '1'
  403.         if 'DEBCONF_DEBUG' not in os.environ:
  404.             os.environ['DEBCONF_DEBUG'] = 'developer|filter'
  405.     # The frontend should take care of displaying a helpful message if
  406.     # we are being run without root privileges.
  407.     if not (options.query and args and args[0] == 'noninteractive'):
  408.         try:
  409.             if oem_config:
  410.                 logfile = '/var/log/oem-config.log'
  411.             else:
  412.                 logfile = '/var/log/installer/debug'
  413.             log = os.open(logfile, os.O_WRONLY | os.O_CREAT | os.O_APPEND)
  414.             os.dup2(log, 2)
  415.             os.close(log)
  416.             sys.stderr = os.fdopen(2, 'a', 1)
  417.             if oem_config:
  418.                 print >>sys.stderr, "Ubiquity %s (oem-config)" % VERSION
  419.             else:
  420.                 print >>sys.stderr, "Ubiquity %s" % VERSION
  421.         except (IOError, OSError), err:
  422.             if err.errno != errno.EACCES:
  423.                 raise
  424.  
  425.     # Default to enabling internal (non-debconf) debugging except for when
  426.     # using --automatic.
  427.     if 'UBIQUITY_DEBUG_CORE' not in os.environ:
  428.         if options.automatic:
  429.             os.environ['UBIQUITY_DEBUG_CORE'] = '1'
  430.  
  431.     # Clean up old state.
  432.     for name in ('apt-installed', 'apt-install-direct', 'remove-kernels'):
  433.         path = os.path.join('/var/lib/ubiquity', name)
  434.         if os.path.exists(path):
  435.             os.unlink(path)
  436.     shutil.rmtree("/var/lib/partman", ignore_errors=True)
  437.  
  438.     if oem_config and not options.query:
  439.         disable_autologin()
  440.  
  441.     if args:
  442.         install(args[0], query=options.query)
  443.     else:
  444.         install(query=options.query)
  445.  
  446.     if oem_config:
  447.         run_oem_hooks()
  448.     im_switch.kill_im()
  449.  
  450. if __name__ == '__main__':
  451.     # Are we running as ubiquity or oem-config?
  452.     oem_config = False
  453.     script_name = os.path.basename(sys.argv[0])
  454.     if script_name == 'oem-config':
  455.         oem_config = True
  456.  
  457.     main(oem_config)
  458.  
  459. # vim:ai:et:sts=4:tw=80:sw=4:
  460.